#ifndef _______boid_h_
#define _______boid_h_

#include "stdafx.h"
//#include <Ogre.h>
//#include "MyCommon.h"

using namespace Ogre;
using namespace MyCommon;

typedef MyCommon::Vector3 MyVec3;
typedef MyCommon::Real MyReal;
typedef Ogre::Vector3 OgreVec;
typedef Ogre::Radian OgreRadian;
typedef MyCommon::Radian MyRadian;
typedef Ogre::Real OgreReal;


class World;
class SteeringBehavior;

class Boid
{
private:

	//a pointer to the world data. So a boid can access any obstacle,
	//path, wall or agent data
	World* mWorld;
	//the steering behavior class
	SteeringBehavior* mSteering;
	//some steering behaviors give jerky looking movement. The
	//following members are used to smooth the boid's heading
	Smoother<MyVec3>* mHeadingSmoother;
	//this vector represents the average of the boid's heading
	//vector smoothed over the last few frames
	MyVec3 mSmoothedHeading;
	//when true, smoothing is active
	bool mSmoothingOn;

	Entity* mEntity;
	AnimationState* mAnimationState; 
	MyVec3 mVelocity;
	//a normalized vector pointing in the direction the entity is heading. 
	MyVec3 mHeading;
	//a vector perpendicular to the heading vector
	MyVec3 mSide;

	MyReal mMass;

	//the maximum speed this entity may travel at.
	MyReal mMaxSpeed;
	//the maximum force this entity can produce to power itself 
	//(think rockets and thrust)
	MyReal mMaxForce;
	//the maximum rate (radians per second)this Boid can rotate         
	MyRadian mMaxTurnRate;

	double mTimeElapsed;

	
public:

	Boid(String entName,String meshName,SceneManager* sceneManager,World* world,
		MyVec3 pos, MyReal radius,MyVec3 velocity,MyReal maxSpeed,MyVec3 heading,
		MyReal mass,MyRadian turnRate,MyReal maxForce);
	~Boid();
	
	void Update(double time_elapsed);

	Entity* getEntity() { return mEntity;	}

	const OgreVec& getPos() const
	{
		if(mEntity==NULL) OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,"Ooops, NULL entity","");
		Ogre::SceneNode* node = getParentSceneNode();
		return node->getPosition();
	}

	void setPos(const OgreVec& pos)
	{
		if(mEntity==NULL) OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,"Ooops, NULL entity","");
		getParentSceneNode()->setPosition(pos);
	}
	Ogre::SceneNode* getParentSceneNode() const {return mEntity->getParentSceneNode(); }

	MyVec3 getVelocity()const{return mVelocity;}
	void setVelocity(const MyVec3& NewVel){mVelocity = NewVel;}

	MyReal getMass() const { return mMass;}
	MyVec3 getSide()const{ return mSide;}

	MyReal getMaxSpeed() const {return mMaxSpeed;}                       
	void setMaxSpeed(MyReal new_speed){mMaxSpeed = new_speed;}

	MyReal getMaxForce()const{return mMaxForce;}
	void setMaxForce(MyReal mf){mMaxForce = mf;}

	bool isSpeedMaxedOut()const{return mMaxSpeed*mMaxSpeed >= mVelocity.squaredLength();}
	MyReal getSpeed()const{return mVelocity.length();}
	MyReal getSpeedSq()const{return mVelocity.squaredLength();}

	MyVec3 getHeading()const{return mHeading;}
	void setHeading(MyVec3 new_heading);
	bool rotateHeadingToFacePosition(OgreVec target);

	MyRadian maxTurnRate()const{return mMaxTurnRate;}
	void setMaxTurnRate(MyRadian val){mMaxTurnRate = val;}

	SteeringBehavior* const Steering() const {return mSteering;}
	World* getWorld() {return mWorld;}
	MyVec3 SmoothedHeading() { return mSmoothedHeading;}
	bool IsSmoothingOn()const{return mSmoothingOn;}
	void SetSmoothingOn(){mSmoothingOn = true;}
	void SetSmoothingOff(){mSmoothingOn = false;}
	void ToggleSmoothing(){mSmoothingOn = !mSmoothingOn;}
	double getTimeElapsed() const { return mTimeElapsed; }

};

#endif